package com.ztom.top100;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

/**
 * 二叉树中序遍历
 * <p>
 * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
 *
 * @author ZhangTao
 */
public class Code37InorderTraversal {

    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode() {
        }

        TreeNode(int val) {
            this.val = val;
        }

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

    /**
     * 递归
     *
     * @param root
     * @return
     */
    public List<Integer> inorderTraversal2(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        process(root, res);
        return res;
    }

    private void process(TreeNode node, List<Integer> res) {
        if (node == null) {
            return;
        }
        process(node.left, res);
        res.add(node.val);
        process(node.right, res);
    }

    /**
     * 非递归
     *
     * @param root
     * @return
     */
    public List<Integer> inorderTraversal1(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }

        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode node = root;
        while (!stack.isEmpty() || node != null) {
            if (node != null) {
                stack.addLast(node);
                // 一直到左孩子为空
                node = node.left;
            } else {
                node = stack.pollLast();
                res.add(node.val);
                // 去右树
                node = node.right;
            }
        }
        return res;
    }

    /**
     * morris 遍历
     *
     * @param root
     * @return
     */
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }

        TreeNode cur = root;
        TreeNode mostRight = null;
        while (cur != null) {
            mostRight = cur.left;
            if (mostRight != null) {
                // 有左树, 找到左孩子最右节点
                while (mostRight.right != null && mostRight.right != cur) {
                    mostRight = mostRight.right;
                }
                if (mostRight.right == null) {
                    // 第一次到达不收集
                    mostRight.right = cur;
                    cur = cur.left;
                } else {
                    // 第二次到达收集
                    res.add(cur.val);
                    mostRight.right = null;
                    cur = cur.right;
                }
            } else {
                // 无左树, 第一次到达就收集
                res.add(cur.val);
                cur = cur.right;
            }
        }
        return res;
    }
}
